package com.cy.ppj.service.product.impl;

import com.cy.ppj.comm.constant.CacheConstants;
import com.cy.ppj.comm.utils.CommonUtils;
import com.cy.ppj.dao.mapper.city.CityMapper;
import com.cy.ppj.dao.mapper.product.*;
import com.cy.ppj.dao.mapper.user.UserInfoMapper;
import com.cy.ppj.model.PageBean;
import com.cy.ppj.model.Result;
import com.cy.ppj.model.ao.product.ProductAddAO;
import com.cy.ppj.model.ao.product.ProductEditAO;
import com.cy.ppj.model.ao.product.ProductRateAO;
import com.cy.ppj.model.domian.city.City;
import com.cy.ppj.model.domian.product.*;
import com.cy.ppj.model.domian.user.UserInfo;
import com.cy.ppj.model.enums.DocsType;
import com.cy.ppj.model.enums.Process;
import com.cy.ppj.model.enums.ProductAttachmentType;
import com.cy.ppj.model.query.ProductAdminQuery;
import com.cy.ppj.model.query.ProductQuery;
import com.cy.ppj.model.query.ProductRecommendAdminQuery;
import com.cy.ppj.model.query.RecommendedProductsAdminQuery;
import com.cy.ppj.model.enums.ProductStatus;
import com.cy.ppj.model.enums.RecommendType;
import com.cy.ppj.model.enums.account.BrokerLevel;
import com.cy.ppj.model.vo.ProductAdminVO;
import com.cy.ppj.model.vo.ProductDetailAdminVO;
import com.cy.ppj.model.vo.ProductDetailVO;
import com.cy.ppj.model.vo.ProductExtendPathVO;
import com.cy.ppj.model.vo.ProductRecommendAdminVO;
import com.cy.ppj.model.vo.ProductVO;
import com.cy.ppj.model.vo.RecommendedProductsAdminVO;
import com.cy.ppj.service.BaseService;
import com.cy.ppj.service.account.BrokerService;
import com.cy.ppj.service.product.ProductService;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class ProductServiceImpl extends BaseService implements ProductService {

    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private ProductTagMapper productTagMapper;
    @Autowired
    private ProductTypeMapper productTypeMapper;
    @Autowired
    private ProductRateMapper productRateMapper;
    @Autowired
    private ProductProcessMapper productProcessMapper;
    @Autowired
    private ProductDocsMapper productDocsMapper;
    @Autowired
    private ProductRecommendMapper productRecommendMapper;
    @Autowired
    private CityMapper cityMapper;
    @Autowired
    private ProductCityMapper productCityMapper;
    @Autowired
    private ProductAttachmentMapper productAttachmentMapper;
    @Autowired
    private BrokerService brokerService;
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    @Transactional
    public void addProduct(ProductAddAO productaddAO) {
        //产品基本信息
        Product product = new Product();
        //默认下架
        product.setStatus(ProductStatus.DOWN);
        product.setCreateTime(new Date());
        BeanUtils.copyProperties(productaddAO, product);
        product.setSignProcess(Stream.of(productaddAO.getContractProcesses()).collect(Collectors.joining(",")));
        if(StringUtils.isEmpty(product.getHotOrder())) {
        	//如果前端页面填的产品排序为空，则按照当前表里最大值+1
        	int maxHotOrder = productMapper.selectMaxHotOrder();
        	product.setHotOrder(maxHotOrder + 1);
        }
        productMapper.insertSelective(product);
        //保存
        //保存标签
        Long[] tagIds = productaddAO.getTagIds();
        productTagMapper.insertBatchWhenTagExist(product.getId(), tagIds);
        //保存城市
        Long[] cityIds = productaddAO.getCityIds();
        productCityMapper.insertBatchWhenCityExist(product.getId(), cityIds);
        //保存利率设置
        Date createTime = new Date();
        List<ProductRate> productRateList = new ArrayList<>();
        productaddAO.getRateOptions().stream().forEach(r -> {
            ProductRate rate = new ProductRate();
            rate.setProductId(product.getId());
            rate.setPeriods(r.getPeriods());
            rate.setRate(r.getRate());
            rate.setRepayType(r.getRepayType());
            rate.setCreateTime(createTime);
            productRateList.add(rate);
        });
        productRateMapper.insertBatch(productRateList);
        //添加条件
        List<ProductDocs> productDocsList = new ArrayList<>();
        //准入条件
        String accessCondtion = productaddAO.getAccessConditon();
        productDocsList.add(CommonUtils.getProductDosc(accessCondtion, DocsType.ACCESS_CONDITION));
        //征信条件条件
        String creditCondition = productaddAO.getCreditCondition();
        productDocsList.add(CommonUtils.getProductDosc(creditCondition, DocsType.CREDIT_CONDITION));
        //所需材料
        String requiredInfomation = productaddAO.getRequiredInfomation();
        productDocsList.add(CommonUtils.getProductDosc(requiredInfomation, DocsType.REQUIRED_INFORMATION));
        //去掉空的
        productDocsList = productDocsList.stream().filter(d -> d != null).collect(Collectors.toList());
        productDocsList.stream().forEach(d -> {
            d.setProductId(product.getId());
            d.setCreateTime(createTime);
        });
        //批量导入
        productDocsMapper.insertBatch(productDocsList);

        // 保存产品推广图片地址
        if(product.getExtend()) {
        	// 只有选择推广的时候，才保存推广图片地址
        	List<ProductAttachment> productAttachmentList = new ArrayList<>();
         	// 推广二维码地址
        	String extendQRCodePath = productaddAO.getExtendQRCodePath();
        	productAttachmentList.add(CommonUtils.getProductAttachment(extendQRCodePath, ProductAttachmentType.EXTEND_QR_CODE));
        	// 推广页图片地址
        	String extendPagePath = productaddAO.getExtendPagePath();
        	productAttachmentList.add(CommonUtils.getProductAttachment(extendPagePath, ProductAttachmentType.EXTEND_PAGE));
        	productAttachmentList.stream().forEach(p -> {
        		p.setProductId(product.getId());
        		p.setCreateTime(createTime);
        		p.setUpdateTime(createTime);
        	});
        	//批量新增
        	productAttachmentMapper.insertBatch(productAttachmentList);
        }
        
        //产品流程
        if(Stream.of(productaddAO.getProcesses()).anyMatch(p -> p.equals(Process.REVIEW))) {
        	// 如果流程有‘复议’,那‘电核’、‘放款’流程也必须要有
        	boolean flag = Stream.of(productaddAO.getProcesses()).noneMatch(p -> p.equals(Process.CALL_VERIFY))
        			|| Stream.of(productaddAO.getProcesses()).noneMatch(p -> p.equals(Process.LOAN));
        	state(!flag, "复议必须绑定电核与放款");
        }
        //先排序
        Process[] processes = productaddAO.getProcesses();
        //Stream.of(processes).sorted(Comparator.comparing(Process::getArrOrder));
        Collections.sort(Arrays.asList(processes), Comparator.comparing(Process::getArrOrder));
        productProcessMapper.insertBatch(product.getId(), processes, createTime);
    }

    @Override
    @Transactional
    @CacheEvict(value = CacheConstants.CACHE_PRODUCT_TAG, allEntries = true, beforeInvocation = true)
    public void addType(String name) {
        //查询名称是否存在
        boolean isExists = productTypeMapper.isNameExists(name);
        state(!isExists, "该类型已存在");
        ProductType productType = new ProductType();
        productType.setName(name);
        productType.setCreateTime(new Date());
        //入库
        productTypeMapper.insertSelective(productType);
    }

    @Override
    @Transactional
    @CacheEvict(value = CacheConstants.CACHE_PRODUCT_TAG, allEntries = true, beforeInvocation = true)
    public void updateType(ProductType productType) {
        //查询名称是否存在
        boolean isExists = productTypeMapper.isNameExists(productType.getName());
        state(!isExists, "该类型已存在");
        //更新
        productType.setUpdateTime(new Date());
        productTypeMapper.updateByPrimaryKeySelective(productType);
    }

    @Override
    @Cacheable(value = CacheConstants.CACHE_PRODUCT_TAG)
    public List<ProductType> allTypesInCache() {
        List<ProductType> productTypes = productTypeMapper.selectAll();
        productTypes.stream().forEach(p -> {
            p.setCreateTime(null);
            p.setUpdateTime(null);
        });
        return productTypes;
    }

    @Override
    @Transactional
    @Caching(evict = {
            @CacheEvict(value = CacheConstants.CACHE_VALUE_2H, beforeInvocation = true, key = "'getProcessByProductIdInCache-'+#productEditAO.id")
    })
    public void updateProduct(ProductEditAO productEditAO) {
        Product product = new Product();
        product.setUpdateTime(new Date());
        BeanUtils.copyProperties(productEditAO, product);
        product.setSignProcess(Stream.of(productEditAO.getContractProcesses()).collect(Collectors.joining(",")));
        int maxHotOrder = productMapper.selectMaxHotOrder();
        if(StringUtils.isEmpty(product.getHotOrder())) {
        	//如果前端页面填的产品排序为空，则按照当前表里最大值+1
        	product.setHotOrder(maxHotOrder + 1);
        }
        productMapper.updateByPrimaryKeySelective(product);
        //更新利率设置
        List<ProductRateAO> rateOptions = productEditAO.getRateOptions();
        List<ProductRate> productRateList = new ArrayList<>();
        List<Integer> periodsList = new ArrayList<>();
        rateOptions.stream().forEach(r -> {
            ProductRate rate = new ProductRate();
            rate.setProductId(product.getId());
            rate.setPeriods(r.getPeriods());
            rate.setRate(r.getRate());
            rate.setRepayType(r.getRepayType());
            rate.setCreateTime(new Date());
            productRateList.add(rate);
            periodsList.add(r.getPeriods());
        });
        //除了上传上来的ID，其他都删除
        productRateMapper.deletaBatch(productEditAO.getId(), periodsList);
        productRateMapper.insertBatch(productRateList);
        //更新标签
        Long[] tagIds = productEditAO.getTagIds();
        productTagMapper.insertBatchWhenTagExist(productEditAO.getId(), tagIds);
        productTagMapper.deleteBatch(productEditAO.getId(), tagIds);
        //更新城市
        Long[] cityIds = productEditAO.getCityIds();
        productCityMapper.insertBatchWhenCityExist(productEditAO.getId(), cityIds);
        productCityMapper.deleteBatchWhenCityNotIn(productEditAO.getId(), cityIds);
        
        List<ProductDocs> productDocsList = new ArrayList<>();
        //准入条件
        String accessCondtion = productEditAO.getAccessConditon();
        productDocsList.add(CommonUtils.getProductDosc(accessCondtion, DocsType.ACCESS_CONDITION));
        //征信条件条件
        String creditCondition = productEditAO.getCreditCondition();
        productDocsList.add(CommonUtils.getProductDosc(creditCondition, DocsType.CREDIT_CONDITION));
        //所需材料
        String requiredInfomation = productEditAO.getRequiredInfomation();
        productDocsList.add(CommonUtils.getProductDosc(requiredInfomation, DocsType.REQUIRED_INFORMATION));
        Date now = new Date();
        List<DocsType> docsTypes = new ArrayList<>();
        //批量处理
        productDocsList = productDocsList.stream().filter(p -> p != null).collect(Collectors.toList());
        productDocsList.stream().forEach(p -> {
            p.setCreateTime(now);
            p.setProductId(productEditAO.getId());
            docsTypes.add(p.getType());
        });
        productDocsMapper.insertBatch(productDocsList);
        productDocsMapper.deleteBatch(productEditAO.getId(), docsTypes);

        // 保存产品推广图片地址
        if(product.getExtend()) {
        	// 只有选择推广的时候，才保存推广图片地址
        	List<ProductAttachment> productAttachmentList = new ArrayList<>();
         	// 推广二维码地址
        	String extendQRCodePath = productEditAO.getExtendQRCodePath();
        	productAttachmentList.add(CommonUtils.getProductAttachment(extendQRCodePath, ProductAttachmentType.EXTEND_QR_CODE));
        	// 推广页图片地址
        	String extendPagePath = productEditAO.getExtendPagePath();
        	productAttachmentList.add(CommonUtils.getProductAttachment(extendPagePath, ProductAttachmentType.EXTEND_PAGE));
        	productAttachmentList.stream().forEach(p -> {
        		p.setProductId(product.getId());
        		p.setCreateTime(now);
        		p.setUpdateTime(now);
        	});
        	//批量新增
        	productAttachmentMapper.insertBatch(productAttachmentList);
        	productAttachmentMapper.deleteByUpdateTime(productEditAO.getId(), now);
        }

        if(Stream.of(productEditAO.getProcesses()).anyMatch(p -> p.equals(Process.REVIEW))) {
        	// 如果流程有‘复议’,那‘电核’、‘放款’流程也必须要有
        	boolean flag = Stream.of(productEditAO.getProcesses()).noneMatch(p -> p.equals(Process.CALL_VERIFY))
        			|| Stream.of(productEditAO.getProcesses()).noneMatch(p -> p.equals(Process.LOAN));
        	state(!flag, "复议必须绑定电核与放款");
        }

        //产品流程编辑,先全删，再重新插入数据
        productProcessMapper.deleteByProductId(productEditAO.getId());
        Process[] processes = productEditAO.getProcesses();
        Collections.sort(Arrays.asList(processes), Comparator.comparing(Process::getArrOrder));
        productProcessMapper.insertBatch(productEditAO.getId(), processes, now);
        //删除没有提交上来的流程
        //productProcessMapper.deleteBatch(productEditAO.getId(), productEditAO.getProcesses());
    }

    @Override
    @Cacheable(value = CacheConstants.CACHE_VALUE_2H, key = "'getProcessByProductIdInCache-'+#productId")
    public List<Process> getProcessByProductIdInCache(Long productId) {
        return productProcessMapper.selectProcessByProductId(productId);
    }

    @Override
    public PageBean<ProductAdminVO> adminProducts(ProductAdminQuery productAdminQuery) {
        int total = productMapper.adminProductCount(productAdminQuery);
        List<ProductAdminVO> list = new ArrayList<>();
        if (total > 0) {
            productAdminQuery.startPage();
            list = productMapper.adminProducts(productAdminQuery);
        }
        return new PageBean<>(list, total);
    }

	@Override
	public PageBean<ProductVO> homeProducts(ProductQuery productQuery) {
		int total = productMapper.homeProductCount(productQuery);
		List<ProductVO> list = new ArrayList<>();
		if(total > 0) {
			productQuery.startPage();
			list = productMapper.homeProducts(productQuery);
		}
		return new PageBean<>(list, total);
	}

	@Override
	public ProductDetailVO queryProductDetail(Long productId, Long userId) {
		ProductDetailVO productDetailVO = productMapper.queryProductDetail(productId);
		state(productDetailVO != null, "产品信息不存在");
		// 找到当前登录用户
		UserInfo userInfo = new UserInfo();
		userInfo.setUserId(userId);
		userInfo = userInfoMapper.selectOne(userInfo);
		BigDecimal brokerRate = BigDecimal.ZERO;
		if(userInfo != null) {
			if(userInfo.getNewUser()) {
				//新注册用户，体验钻石佣金率
				brokerRate = brokerService.queryBrokerRate(BrokerLevel.DIAMOND);
			}else {
				brokerRate = brokerService.queryBrokerRate(userInfo.getLevel());
			}
		}
		productDetailVO.setBrokerRate(brokerRate);
		return productDetailVO;
	}


	@Override
	public PageBean<ProductVO> queryProductList(ProductQuery productQuery) {
		//处理标签id字符串
		if(!StringUtils.isEmpty(productQuery.getTagIdStr())) {
			String[] str = productQuery.getTagIdStr().split(",");
			List<Long> tagIdList = new ArrayList<>();
			for(String s : str) {
				tagIdList.add(Long.valueOf(s));
			}
			productQuery.setTagIdLists(tagIdList);
		}
		int total = productMapper.queryProductListCount(productQuery);
		List<ProductVO> list = new ArrayList<>();
		if(total > 0) {
			productQuery.startPage();
			list = productMapper.queryProductList(productQuery);
		}
		return new PageBean<>(list, total);
	}

	@Override
	public Result queryProductDetailAdmin(Long productId) {
		ProductDetailAdminVO product = productMapper.queryProductDetailAdmin(productId);
		state(product != null, "该产品不存在");
		if(!StringUtils.isEmpty(product.getSignProcess())) {
			product.setContractProcesses(product.getSignProcess().split(","));
		}
		List<ProductRate> rateList = productRateMapper.queryRateByProductId(productId);
		rateList.stream().forEach(r -> {
			r.setCreateTime(null);
			r.setUpdateTime(null);
		});
		List<Process> process = productProcessMapper.selectProcessByProductId(productId);
		List<ProductDocs> productDocs = productDocsMapper.queryByProductId(productId);
		productDocs.stream().forEach(n -> {
			n.setCreateTime(null);
			n.setUpdateTime(null);
		});
		List<Tag> tagList = tagMapper.queryTagByProductId(productId);
		tagList.stream().forEach(n -> {
			n.setCreateTime(null);
			n.setUpdateTime(null);
		});
		List<City> cityList = cityMapper.selectCityListByProductId(productId);
		List<ProductAttachment> productAttachments = productAttachmentMapper.selectByProductId(productId);
		productAttachments.stream().forEach(pa -> {
			if(ProductAttachmentType.EXTEND_QR_CODE.equals(pa.getType())) {
				product.setExtendQRCodePath(pa.getPath());
			}
			if(ProductAttachmentType.EXTEND_PAGE.equals(pa.getType())) {
				product.setExtendPagePath(pa.getPath());
			}
		});
		Map<String, Object> map = new HashMap<>();
		map.put("product", product);
		map.put("rateList", rateList);
		map.put("process", process);
		map.put("tagList", tagList);
		map.put("cityList", cityList);
		productDocs.stream().forEach(d -> {
			if(DocsType.ACCESS_CONDITION.equals(d.getType())) {
				map.put("accessCondition", d.getContext());
			}
			if(DocsType.CREDIT_CONDITION.equals(d.getType())) {
				map.put("creditCondition", d.getContext());
			}
			if(DocsType.REQUIRED_INFORMATION.equals(d.getType())) {
				map.put("requiredInformation", d.getContext());
			}
		});
		return Result.success("查询成功", map);
	}

	@Override
	@Transactional
	public Result updateProductStatus(Long productId, ProductStatus productStatus) {
		Product product = new Product();
		product.setId(productId);
		product.setStatus(productStatus);
		product.setUpdateTime(new Date());
		int result = productMapper.updateByPrimaryKeySelective(product);
		state(result == 1, "更改产品状态失败");
		return Result.success();
	}

	@Override
	@Transactional
	public void addProductRecommend(Long productId, RecommendType type) {
		Date time = new Date();
		ProductRecommend pr = new ProductRecommend();
		pr.setProductId(productId);
		pr.setType(type);
		pr.setCreateTime(time);
		pr.setUpdateTime(time);
		productRecommendMapper.insertOnDuplicateKeyUpdate(pr);
	}

	@Override
	public PageBean<ProductRecommendAdminVO> queryProductRecommendAdminList(
			ProductRecommendAdminQuery productRecommendAdminQuery) {
		int total = productRecommendMapper.queryProductRecommendAdminCount(productRecommendAdminQuery);
		List<ProductRecommendAdminVO> list = new ArrayList<>();
		if(total > 0) {
			productRecommendAdminQuery.startPage();
			list = productRecommendMapper.queryProductRecommendAdminList(productRecommendAdminQuery);
		}
		return new PageBean<>(list, total);
	}

	@Override
	public Result queryPeriodsByOrderId(Long orderId) {
		return Result.success("查询成功", productRateMapper.queryPeriodsByOrderId(orderId));
	}

	@Override
	public ProductExtendPathVO selectPathByProductIdAndType(Long productId, ProductAttachmentType type) {
		ProductExtendPathVO productExtendPathVO = productAttachmentMapper.selectPathByProductIdAndType(productId, type);
		state(productExtendPathVO != null, "该产品未配置推广图片");
		return productExtendPathVO;
	}

	@Override
	public Product selectProduct(Product product) {
		product = productMapper.selectOne(product);
		state(product != null, "该产品不存在");
		return product;
	}

	@Override
	@Transactional
	public void deleteProductRecommendById(Long id) {
		productRecommendMapper.deleteByPrimaryKey(id);
	}

	@Override
	public PageBean<RecommendedProductsAdminVO> selectRecommendedProductsAdminList(
			RecommendedProductsAdminQuery query) {
		int total = productMapper.selectRecommendedProductsAdminCount(query);
		List<RecommendedProductsAdminVO> list = new ArrayList<>();
		if(total > 0) {
			query.startPage();
			list = productMapper.selectRecommendedProductsAdminList(query);
		}
		return new PageBean<>(list, total);
	}

	@Override
	public List<Product> selectAllProductsIncache() {
		Product product = new Product();
		product.setStatus(ProductStatus.UP);
		List<Product> list = productMapper.select(product);
		List<Product> newList = new ArrayList<>();
		list.stream().forEach(p -> {
			Product temp = new Product();
			temp.setId(p.getId());
			temp.setName(p.getName());
			newList.add(temp);
		});
		return newList;
	}

	@Override
	public List<ProductRate> selectProductRateListByProductId(Long productId) {
		List<ProductRate> list = productRateMapper.queryRateByProductId(productId);
		list.stream().forEach(pr -> {
			pr.setId(null);
			pr.setCreateTime(null);
			pr.setUpdateTime(null);
		});
		return list;
	}

	@Override
	@Cacheable(value = CacheConstants.CACHE_VALUE_24H)
	public List<Product> selectProductsForAddOrderInCache() {
		List<Product> list = productMapper.selectProductsForAddOrder();
		return list;
	}
}
